//
//  ReflectUtils.m
//  json-oc
//
//  Created by shk on 15/1/7.
//  Copyright (c) 2015年 com.shk.study. All rights reserved.
//

#import "ReflectUtils.h"

@implementation ReflectUtils


+ (Class) getEntityByClassName:(NSString *)className{
    const char *name = [className UTF8String];
    return objc_getClass(name);
}

+ (NSString *) getClassNameByClass:(Class)classEntity{
    id obj = [[classEntity alloc] init];
    const char *name = object_getClassName(obj);
    return [NSString stringWithUTF8String:name];
}

+ (NSArray*)getPropertysByClass:(Class) cls{
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(cls, &outCount);
    NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:outCount];
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        [result addObject:(__bridge id)(property)];
    }
    free(properties);
    return result;
}


+ (NSArray*)getPropertyNamesByClass:(Class) cls{
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(cls, &outCount);
    NSMutableArray *propertyNames = [[NSMutableArray alloc] initWithCapacity:outCount];
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        [propertyNames addObject:propertyName];
    }
    free(properties);
    return propertyNames;
}



+ (NSDictionary *)getPropertiesForClass:(Class)cls {
    if (cls == NULL) {
        return nil;
    }
    NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
    
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(cls, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = [self getPropertyType:property];
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSArray *systemExcludedProperties = @[@"observationInfo",@"hash",@"description",@"debugDescription",@"superclass"];
            if (![systemExcludedProperties containsObject:propertyName]) {
                NSString *propertyType = [NSString stringWithUTF8String:propType];
                results[propertyName] = propertyType;
            }
        }
    }
    free(properties);
    return [NSDictionary dictionaryWithDictionary:results];// returning a copy here to make sure the dictionary is immutable
}


+ (NSDictionary *)getPropertiesForClassWithSupperClass:(Class)cls {
    NSMutableDictionary *results = [[NSMutableDictionary alloc] init];
    [results addEntriesFromDictionary:[self getPropertiesForClass:cls]];
    if ([cls superclass] != [NSObject class]) {
        [results addEntriesFromDictionary:[self getPropertiesForClass:[cls superclass]]];
    }
    return [NSDictionary dictionaryWithDictionary:results];
}






+ (const char *) getPropertyType :(objc_property_t) property {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // it's a C primitive type:
            /*
             if you want a list of what will be returned for these primitives, search online for
             "objective-c" "Property Attribute Description Examples"
             apple docs list plenty of examples of what you get for int "i", long "l", unsigned "I", struct, etc.
             */
            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSUTF8StringEncoding];
            return (const char *)[name cStringUsingEncoding:NSUTF8StringEncoding];
        } else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            return "id";// it's an ObjC id type
        } else if (attribute[0] == 'T' && attribute[1] == '@') {// it's another ObjC object type
            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSUTF8StringEncoding];
            return (const char *)[name cStringUsingEncoding:NSUTF8StringEncoding];
        }
    }
    return "";
}









@end